home *** CD-ROM | disk | FTP | other *** search
Wrap
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # socket.c # igc.c # parse.c # ascii.c # board.c # numbers.h # igc.h # Makefile # igc.6 # This archive created: Sat Dec 5 23:18:01 1992 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' IGS - Ascii Client by Adrian Mariano adrian@u.washington.edu adrian on igs This is an ascii client program for the Internet Go Server. Its purpose is to provide a useable interface to the server with ASCII character drawn Go boards. This program requires UNIX with sockets capability. Read the Makefile for instructions on compiling. SHAR_EOF fi if test -f 'socket.c' then echo shar: "will not over-write existing file 'socket.c'" else cat << \SHAR_EOF > 'socket.c' #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netdb.h> #ifndef WINS /* Usually want this... */ #include <netinet/in.h> #else /* ... but need these for WINS. */ #include <sys/in.h> #include <sys/inet.h> #endif #include <fcntl.h> #include <sys/errno.h> #include <stdio.h> #ifndef FD_ZERO #include <sys/select.h> #endif #include "igc.h" /* For some odd systems, which don't put this in errno.h. */ extern int errno; char servename[80]; int serveport; int sock; char inbuf[1000]; int inptr = 0; sethost(s) char *s; { strcpy(servename, s); } setport(s) int s; { serveport = s; } void close_connection() { close(sock); } #ifdef DEBUG FILE *blah; #endif int open_connection() { struct sockaddr_in server; struct hostent *hp; int ipn; printf("Opening connection to %s %d\n", servename, serveport); #ifdef DEBUG { int d; char n[444]; d = 0; do { sprintf(n, "dump%d.igc", d); blah = fopen(n, "r"); if (!blah) { blah = fopen(n, "w"); if (blah) printf("Creating dump file %s\n", n); break; } close(blah); d++; if (d > 9) { printf("Too many dump files. Delete dump files (dump?.igc)? "); fgets(n, 443, stdin); if (n[0] != 'Y' && n[0] != 'y') exit(1); for (d = 0; d < 10; d++) { sprintf(n, "dump%d.igc", d); unlink(n); } blah = fopen("dump0.igc", "w"); if (!blah) { printf("File open error. Cannot create dump file\n"); exit(1); } break; } } while (1); if (!blah) { printf("File open error. Cannot create dump file.\n"); exit(1); } } #endif if (sscanf(servename, "%d.%d.%d.%d", &ipn, &ipn, &ipn, &ipn) == 4) server.sin_addr.s_addr = inet_addr(servename); else { hp = gethostbyname(servename); if (hp == 0) { puts("Unknown host"); return -1; } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); } server.sin_family = AF_INET; server.sin_port = htons(serveport); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return -1; } if (connect(sock, (struct sockaddr *) & server, sizeof(struct sockaddr_in)) < 0) { perror("connect"); return -1; } return 0; } sendstr(buf) char *buf; { #ifdef DEBUG if (strlen(buf) && blah) fprintf(blah, ">%s<\n", buf); #endif write(sock, buf, strlen(buf)); } int eatchar = 0; int handlechar(retbuf, in) char *retbuf; char in; { if (in == '\r') return 0; #ifdef DEBUG fputc(in, blah); #endif if (eatchar) { eatchar--; return 0; } if (in == '\377') { eatchar = 2; return 0; } if (in == '\n') { inbuf[inptr] = 0; strcpy(retbuf, inbuf); inptr = 0; return 1; } else { inbuf[inptr++] = in; if (doneline(inbuf, inptr)) { inbuf[inptr] = 0; strcpy(retbuf, inbuf); inptr = 0; return 1; } } return 0; } int bufdata = 0, bufptr = 0; char thebuf[1000]; int pollserver(retbuf, checkstdin) char *retbuf; int checkstdin; { int sel; fd_set readers; FD_ZERO(&readers); while (1) { while (bufdata) { bufdata--; if (handlechar(retbuf, thebuf[bufptr++])) return 1; } bufptr = 0; if (checkstdin) FD_SET(0, &readers); /* Check stdin */ FD_SET(sock, &readers); sel = select(sock + 1, &readers, NULL, NULL, (struct timeval *) 0); if (sel == -1) { if (errno != EINTR) { /* ^Z will do this */ perror("select"); return -1; } continue; } if (FD_ISSET(sock, &readers)) { bufdata = read(sock, thebuf, 1000); if (!bufdata) return -1; if (bufdata < 0) { perror("read"); return -2; } } else if (FD_ISSET(0, &readers)) return KEY; } } SHAR_EOF fi if test -f 'igc.c' then echo shar: "will not over-write existing file 'igc.c'" else cat << \SHAR_EOF > 'igc.c' #include "igc.h" #include <stdio.h> #include <string.h> #include <signal.h> #include <pwd.h> #include "numbers.h" #define RCNAME "/.igcrc" char login[20] = ""; char password[20] = ""; message mesg; /* structure for getting parsed info from * server */ char prefix[21]; /* Text prefix for each outgoing line */ int xcur = -1, ycur = -1; /* Cursor locations on board */ int boardon = 0; /* Is the board being displayed? */ int boardmode = 0; /* Are we on the board? */ int beepcount = 1; /* Number of beeps to send */ int saybeep = 0; /* Beep on say strings? */ int tellbeep = 0; /* Beep on tell strings? */ int ingame = -1; /* Game which is displayed, -1 for none */ int observing = 0; /* Are we observing a game? */ int justpeeked = 0; /* Fixup flag for game number after peek */ int needrestore = 0; /* Need to restore board? (After status) */ int bschange = 0; /* boardsize changed? Used with needrestore */ extern int boardsize; char local[1000], *loc; /* Buffer for characters typed by local user */ struct { char white[21], wrank[10], black[21], brank[10]; int hcap; float komi; int bbyo, wbyo, wtime, btime; } curgame; /* Information about current game */ int (*whosort) (); struct { char name[50]; char site[100]; int port; } sitetable[10] = { { "icsi", "icsib18.icsi.Berkeley.EDU", 6969 }, { "cnam", "cnam.cnam.fr", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 } }; char *getpassword(repeat) int repeat; { if (repeat || !strlen(password)) { printf("Password: "); for (;;) { gets(password); if (strstr(password, "helpigc")) printf("You are entering your password for the Internet Go Server. You will be\nprompted twice for your password if you are creating a new account. Enter\nthe same password twice in this case.\nPassword: "); else if (!strlen(password)) printf("Empty password not allowed.\nPassword: "); else break; } } return password; } char *getloginname(repeat) int repeat; { if (repeat == 1) printf("Login failed.\n"); if (repeat || !strlen(login)) { printf("Login: "); for (;;) { gets(login); if (strstr(login, "helpigc")) printf("You are logging into the Internet Go server. Type a login name now.\nLogin: "); else if (!strlen(login)) printf("Blank names not allowed.\nLogin: "); else break; } } else printf("Logging on as %s\n", login); return login; } putstr(s) char *s; { if (boardon) { addstring(s); addchar('\n'); } else puts(s); } dobeep() { char ch; for (ch = beepcount; ch--;) putchar(7); } readrc() { int id; struct passwd *pw; char *dir, rcfilename[1000]; FILE *rcfile; char *var, *val, line[100]; id = geteuid(); pw = getpwuid(id); dir = pw->pw_dir; strcpy(rcfilename, dir); strcat(rcfilename, RCNAME); if (rcfile = fopen(rcfilename, "rt")) { while (fgets(line, 99, rcfile)) { var = strtok(line, " \t=\n"); if (!var) continue; val = strtok(NULL, " \t=\n"); if (!strcmp(var, "password")) strcpy(password, val); if (!strcmp(var, "login")) strcpy(login, val); if (!strncmp(var, "site", 4) && var[4] >= '0' && var[4] <= '9') { strcpy(sitetable[var[4] - '0'].name, val); val = strtok(NULL, "\t=\n "); strcpy(sitetable[var[4] - '0'].site, val); if (val = strtok(NULL, "\t= \n")) sitetable[var[4] - '0'].port = atoi(val); else sitetable[var[4] - '0'].port = 6969; } if (!strcmp(var, "saybeep")) saybeep = 1; if (!strcmp(var, "nosaybeep")) saybeep = 0; if (!strcmp(var, "tellbeep")) tellbeep = 1; if (!strcmp(var, "notellbeep")) tellbeep = 0; if (!strcmp(var, "beeps")) beepcount = atoi(val); if (!strcmp(var, "inverse")) setinverse(1); if (!strcmp(var, "noinverse")) setinverse(0); if (!strcmp(var, "noinvedge")) setinverseborder(0); if (!strcmp(var, "invedge")) setinverseborder(1); if (!strcmp(var, "edgemarks")) setedgemark(1); if (!strcmp(var, "noedgemarks")) setedgemark(0); if (!strcmp(var, "piecemarks")) setpiecemark(1); if (!strcmp(var, "nopiecemarks")) setpiecemark(0); if (!strcmp(var, "sort")) choosesort(val); if (!strcmp(var, "border")) { if (!val) setborder(' '); else setborder(*val); } if (!strcmp(var, "chars") && val) setchars(val); } } } void myexit(ex) int ex; { if (boardon) endAscii(); exit(ex); } void handletstp() { signal(SIGTSTP, handletstp); if (boardon) suspend(); kill(getpid(), SIGSTOP); if (boardon) { unsuspend(); if (boardmode) boardrefresh(); else serverrefresh(); } } void handleterm() { close_connection(); myexit(0); } int startgame(n) int n; { char str[100], str2[30]; int ret, gotmove; gotmove = 0; sprintf(str, "games %d\n", n); sendstr(str); do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); if (mesg.id == MOVE) { if (mesg.movecount) putstr("%Premature move. Restart game."); else gotmove = 1; } } while (mesg.id != GAMES); if (mesg.gamecount != 1 || mesg.gamelist[0].gnum != n) return -1; if (mesg.gamelist[0].bsize > 19) { putstr("%Boardsize too large"); return -1; } strcpy(curgame.white, mesg.gamelist[0].white); strcpy(curgame.black, mesg.gamelist[0].black); strcpy(curgame.brank, mesg.gamelist[0].brank); strcpy(curgame.wrank, mesg.gamelist[0].wrank); curgame.hcap = mesg.gamelist[0].hcap; curgame.komi = mesg.gamelist[0].komi; if (observing) { addstring("Removing observe\n"); sprintf(str, "observe %d\n", ingame); sendstr(str); do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); } while (mesg.id != PROMPT); observing = 0; } ingame = n; initboard(mesg.gamelist[0].bsize); displaygamenumber(ingame); xcur = ycur = mesg.gamelist[0].bsize / 2; sprintf(str, "%s (%s)", curgame.black, curgame.brank); sprintf(str2, "%s (%s)", curgame.white, curgame.wrank); boardtitle(str, str2); if (gotmove) highlight(0, 0, 0, 0, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); showkomi(curgame.komi); boardon = 1; return 0; } getmoves(n) int n; { char str[20]; sprintf(str, "moves %d\n", n); sendstr(str); } unobserve() { char str[20]; sprintf(str, "observe %d\n", ingame); sendstr(str); } int observegame(n) int n; { int ret; char str[20]; if (n < 0) return 1; /* if (!observing && ingame != -1) { putstr("%Can't observe while * playing."); return 1; } */ if (startgame(n)) return 1; sprintf(str, "observe %d\n", n); sendstr(str); observing = 1; do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); if ((mesg.id == INFO) && !strncmp(mesg.text, "Removing", 8)) putstr("%fatal sync error. Restart igc."); } while (mesg.id != MOVE && mesg.id != UNDO); getmoves(n); return 0; } int peekgame(n) int n; { /* if (!observing && ingame != -1) { putstr("Can't peek while playing."); * return 1; } */ if (startgame(n)) return 1; getmoves(n); justpeeked = 1; setgame(-1); return 0; } setgame(newgame) int newgame; { if (newgame != ingame) { ingame = newgame; displaygamenumber(ingame); } } loadgame(name) char *name; { char str[100]; int ret; sprintf(str, "load %s\n", name); sendstr(str); do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while ((!ret) || (mesg.id != MOVE && mesg.id != ERROR && mesg.id != PROMPT)); if (mesg.id == ERROR) putstr(mesg.text); else if (mesg.id == PROMPT) putstr("%Load error."); else { if (!startgame(mesg.gamenum)) getmoves(mesg.gamenum); } } char *helpmsg = " Server Window\n\ unobserve Stops observing.\n\ peek n Looks at the board for game n\n\ noboard Goes back to full screen mode\n\ clear Clears the window on the right side of the screen\n\ [no]inverse Switches board to/from inverse \n\ [no]invedge Turns on/off inversed edges\n\ [no]piecemarks Turns on/off piece marks\n\ [no]edgemarks Turns on/off edge marks\n\ sort {none|rank|game|name|idle} Chooses sorting order for who command\n\ user <name> Checks output from last who for <name>\n\ chars <list> Sets board characters in client\n\ goto n Goes to a particular move in the current game.\n\ prefix Sets prefix for all outgoing text you type\n\ Start commands with '!' to avoid using the prefix\n\ \n\ ESC switches between windows ^L refreshes the screen\n\ \n\ Board Window\n\ Use number keys (12346789), emacs keys (^P ^N ^F ^B) or rogue keys\n\ (hjklbnyu) to move the cursor.\n\ Press '0', return, or space to move (send position of cursor)\n\ Press '.' or '>' to move forward through game, ',' or '<' to move backwards.\n\ Press 's' to go to start of game, 'e' to go to end of game.\n\ Press 'c' to clear the current move mark."; help() { if (boardon) bigmess(25, helpmsg); else puts(helpmsg); } doargs(argc, argv) int argc; char *argv[]; { int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) { int j; for (j = i; j < 3; j++) argv[j] = argv[j + 1]; strcpy(login, ""); strcpy(password, ""); argc--; break; } } if (argc > 3) { printf("Too many command line arguments\n\n"); exit(3); } if (argc > 1) { for (i = 0; i < 10; i++) if (!strcmp(argv[1], sitetable[i].name)) { sethost(sitetable[i].site); setport(sitetable[i].port); if (argc > 2) { printf("Error: port specified with named host. Don't use a port number\n"); printf("when using the shorthand name for a host.\n\n"); exit(3); } return; } sethost(argv[1]); if (argc > 2) { if (atoi(argv[2])) setport(atoi(argv[2])); else { printf("Illegal port specification\n\n"); exit(3); } } } } weave() { char *copy[MAXWHO]; int i, num; num = mesg.whocount / 2 + (mesg.whocount & 1); for (i = 0; i < num * 2; i++) copy[i] = mesg.who[i]; for (i = 0; i < num; i++) { mesg.who[2 * i] = copy[i]; mesg.who[2 * i + 1] = copy[num + i]; } } #define NAMECOL 12 #define IDLECOL 25 #define RANKCOL 33 #define FLAGCOL 2 #define GAMECOL 10 int namesort(a, b) char **a, **b; { int i; i = strncasecmp(*a + NAMECOL, *b + NAMECOL, 11); if (i < 0) return -1; if (i > 0) return 1; return 0; } /******************** * who sort functions modified by Edward Blair. 9-6-92 On ties, sort by name. * + addition of idlesort to sort on idle time. ********************/ int gamesort(a, b) char **a, **b; { int i; if ((*a)[GAMECOL] != '-' && (*b)[GAMECOL] != '-') { i = strncmp(*a + GAMECOL - 2, *b + GAMECOL - 2, 3); return i ? (i < 0 ? -1 : 1) : namesort(a, b); } if ((*a)[GAMECOL] != '-') return -1; if ((*b)[GAMECOL] != '-') return 1; if ((*a)[FLAGCOL] != (*b)[FLAGCOL]) { if ((*a)[FLAGCOL] == 'X') return -1; if ((*b)[FLAGCOL] == 'X') return 1; if ((*a)[FLAGCOL] == '!') return 1; if ((*b)[FLAGCOL] == '!') return -1; } return ranksort(a, b); } int ranksort(a, b) char **a, **b; { int i; if ((*a)[RANKCOL] == '2') return -1; if ((*b)[RANKCOL] == '2') return 1; if ((*a)[RANKCOL] != (*b)[RANKCOL]) { if ((*a)[RANKCOL] == '?') return 1; if ((*b)[RANKCOL] == '?') return -1; if ((*a)[RANKCOL] == 'R') return 1; if ((*b)[RANKCOL] == 'R') return -1; if ((*a)[RANKCOL] == 'k') return 1; if ((*b)[RANKCOL] == 'k') return -1; if ((*a)[RANKCOL] == 'd') return 1; if ((*b)[RANKCOL] == 'd') return -1; return namesort(a, b); } if ((*a)[RANKCOL] == 'R' || (*a)[RANKCOL] == '?') return namesort(a, b); i = atoi((*a) + RANKCOL - 2) - atoi((*b) + RANKCOL - 2); if ((*a)[RANKCOL] == 'k') i = -i; if (i > 0) return -1; if (i < 0) return 1; return namesort(a, b); } /******************* * idlesort decides whether a or b has been idle longer *******************/ int idlesort(a, b) char **a; char **b; { int i; /* first check the units letter (h,m,s) assume that we don't need to worry * about d. */ if ((*a)[IDLECOL] != (*b)[IDLECOL]) { if ((*a)[IDLECOL] == 'h') return -1; if ((*b)[IDLECOL] == 'h') return 1; if ((*a)[IDLECOL] == 'm') return -1; if ((*b)[IDLECOL] == 'm') return 1; } i = atoi((*b) + IDLECOL - 2) - atoi((*a) + IDLECOL - 2); if (i > 0) return 1; if (i < 0) return -1; return namesort(a, b); } int choosesort(first) char *first; { if (!first) return 1; if (!strcmp(first, "name")) { whosort = namesort; return 0; } if (!strcmp(first, "rank")) { whosort = ranksort; return 0; } if (!strcmp(first, "game")) { whosort = gamesort; return 0; } if (!strcmp(first, "none")) { whosort = 0; return 0; } if (!strcmp(first, "idle")) { whosort = idlesort; return 0; } return 1; } restoregame() { char str[30], str2[30]; if (needrestore) { if (bschange) initboard(bschange); restoremaxmoves(); endgame(); needrestore = 0; sprintf(str, "%s (%s)", curgame.black, curgame.brank); sprintf(str2, "%s (%s)", curgame.white, curgame.wrank); boardtitle(str, str2); highlight(0, 0, 0, -1, curgame.btime, curgame.bbyo, curgame.wtime, curgame.wbyo); displaygamenumber(ingame); } } main(argc, argv) int argc; char *argv[]; { char ch; int ret; puts("\tigc - Ascii Client version 0.60 by Adrian Mariano"); puts(" type 'helpigc' to get client help, 'help' for server help\n"); strcpy(prefix, ""); whosort = namesort; readrc(); sethost(sitetable[0].site); setport(sitetable[0].port); doargs(argc, argv); loc = local; signal(SIGINT, handleterm); signal(SIGTERM, handleterm); signal(SIGHUP, handleterm); signal(SIGTSTP, handletstp); if (open_connection()) handleterm(); puts("Connection established."); mesg.whocount = 0; { char *whoptr; for (whoptr = &(mesg.whodata[0][0]), ret = 0; ret < MAXWHO; ret++, whoptr += 40) mesg.who[ret] = whoptr; } initparser(); do { if (boardon) if (boardmode) boardrefresh(); else serverrefresh(); ret = getmessage(&mesg, 1); if (ret < 0 && ret != KEY) { if (boardon) { endAscii(); boardon = 0; } puts("Connection closed by server."); myexit(0); } if (ret > 0) switch (mesg.id) { case TOOMANY: myexit(0); printf("Too many players. Sorry.\n"); break; case QUITMESG: if (boardon) { endAscii(); boardon = 0; } puts(mesg.text); break; case ONSERVER: printf("\nWarning: Client mode is not set on the IGS. Setting client mode now.\n The message of the day was not displayed. Type 'help motd' to see it.\n You have not been informed if you have messages.\n\n"); break; case BEEP: if (mesg.beep) dobeep(); break; case MOVE: if (!boardon) puts("%Error: isolated move received"); else { int i; restoregame(); sethighlight(0); for (i = 0; i < mesg.movecount - 1; i++) makemove(mesg.moves[i].x, mesg.moves[i].y, mesg.moves[i].movenum, mesg.moves[i].color, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); sethighlight(1); if (mesg.movecount) makemove(mesg.moves[i].x, mesg.moves[i].y, mesg.moves[i].movenum, mesg.moves[i].color, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); curgame.bbyo = mesg.bbyo; curgame.btime = mesg.btime; curgame.wtime = mesg.wtime; curgame.wbyo = mesg.wbyo; setcursor(xcur, ycur); if (!justpeeked) setgame(mesg.gamenum); justpeeked = 0; } break; case UNDO: restoregame(); if (!boardon) puts("%Error: isolated undo received"); else { setgame(mesg.gamenum); undo(); setcursor(xcur, ycur); } break; case SCOREUNDO: restoregame(); if (endgame()) putstr("%score undo error"); else putstr("Scoring undone."); break; case LOAD: if (!startgame(mesg.gamenum)) getmoves(mesg.gamenum); break; case MATCH: startgame(mesg.gamenum); break; case REMOVE: restoregame(); removeGroup(mesg.x, mesg.y); setcursor(xcur, ycur); break; case SCORE: { char str[50]; sprintf(str, " %s (B): %g\n %s (W): %g", mesg.black, mesg.bscore, mesg.white, mesg.wscore); putstr(str); } break; case STATUS: case LOOK: { int pris[2]; char str[30], str2[30]; if (mesg.boardsize > 19) putstr("%Boardsize too big."); else { needrestore = 1; bschange = 0; savemaxmoves(); if (!boardon || boardsize != mesg.boardsize) { if (!boardon) needrestore = 0; else bschange = boardsize; initboard(mesg.boardsize); xcur = ycur = mesg.boardsize / 2; boardon = 1; } pris[0] = mesg.bcap; pris[1] = mesg.wcap; sprintf(str, "%s (%s)", mesg.black, mesg.brank); sprintf(str2, "%s (%s)", mesg.white, mesg.wrank); boardtitle(str, str2); highlight(0, 0, 0, -1, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); drawpris(pris); showboard(mesg.board); displaygamenumber(-2); } } break; case KIBITZ:{ char s[300]; sprintf(s, "%s: %s", mesg.kibitzer, mesg.kibitz); putstr(s); } break; case WHO: { char out[80 * 300]; int i; if (whosort) { qsort(mesg.who, mesg.whocount, sizeof(char *), whosort); weave(); } strcpy(out, mesg.whofirst); for (i = 0; i < mesg.whocount; i++) { strcat(out, i & 1 ? " | " : "\n"); strcat(out, mesg.who[i]); } strcat(out, "\n"); strcat(out, mesg.wholast); if (boardon) bigmess(mesg.lines, out); else putstr(out); } break; case STORED: if (!strlen(mesg.text)) putstr("No stored games"); else putstr(mesg.text); break; case CHKOMI: curgame.komi = mesg.mykomi; showkomi(curgame.komi); case INFO: if (strstr(mesg.text, "Removing")) { observing = 0; setgame(-1); putstr(mesg.text); } else if (mesg.lines > 1 && boardon) bigmess(mesg.lines, mesg.text); else if (strlen(mesg.text)) putstr(mesg.text); break; case PROMPT: if (ingame != -1 && mesg.prompttype == 5) { setgame(-1); observing = 0; } break; case SAY: if (saybeep) dobeep(); putstr(mesg.text); break; case TELL: if (tellbeep) dobeep(); putstr(mesg.text); break; case 0: break; default: if (mesg.lines > 1 && boardon) bigmess(mesg.lines, mesg.text); else if (strlen(mesg.text)) putstr(mesg.text); break; } if (ret == KEY) { ret = read(fileno(stdin), &ch, 1); if (ch == '\r') ch = '\n'; if (ch == 'L' - 64 && boardon) redraw(); else if (ch == 27 && boardon) switchmode(); else if (boardmode) doboardmode(ch); else doservermode(ch); } } while (1); handleterm(); } switchmode() { boardmode = !boardmode; if (boardmode) setcursor(xcur, ycur); } static char *nomoves = "%no moves recorded"; doboardmode(ch) char ch; { char movestr[10]; switch (ch) { case ',': restoregame(); if (backward(1)) putstr(nomoves); break; case '.': restoregame(); if (forward(1)) putstr(nomoves); break; case '<': restoregame(); if (backward(10)) putstr(nomoves); break; case '>': restoregame(); if (forward(10)) putstr(nomoves); break; case 's': restoregame(); if (beginninggame()) putstr(nomoves); break; case 'e': restoregame(); if (endgame()) putstr(nomoves); break; case '1': case 'b': if (++ycur == boardsize) ycur = 0; if (!xcur--) xcur = boardsize - 1; break; case '3': case 'n': if (++ycur == boardsize) ycur = 0; if (++xcur == boardsize) xcur = 0; break; case '7': case 'y': if (!xcur--) xcur = boardsize - 1; if (!ycur--) ycur = boardsize - 1; break; case '9': case 'u': if (!ycur--) ycur = boardsize - 1; if (++xcur == boardsize) xcur = 0; break; case 'B' - 64: case '4': case 'h': if (!xcur--) xcur = boardsize - 1; break; case 'P' - 64: case '8': case 'k': if (!ycur--) ycur = boardsize - 1; break; case 'N' - 64: case '2': case 'j': if (++ycur == boardsize) ycur = 0; break; case 'F' - 64: case '6': case 'l': if (++xcur == boardsize) xcur = 0; break; case 'c': unmark(); break; case '\n': case '\r': case ' ': case '0': sprintf(movestr, "%c%d\n", xcur + 'A' + (xcur + 'A' >= 'I' ? 1 : 0), boardsize - ycur); sendstr(movestr); break; } setcursor(xcur, ycur); } process(comm, dopre) char *comm; int dopre; { char *first; char save[1000]; strcpy(save, comm); first = strtok(comm, " \n\t"); if (!first) return; if (!strcmp(first, "helpigc")) help(); else if (!strcmp(first, "peek") || !strcmp(first, "moves")) { first = strtok(NULL, " \t\n"); if (first) { if (!observing && ingame != -1) putstr("%Can't observe while playing"); else if (observing && ingame == atoi(first)) unobserve(); else if (peekgame(atoi(first))) putstr("%No such game"); } } else if (!strcmp(first, "observe") || !strcmp(first, "ob")) { first = strtok(NULL, " \t\n"); if (first) { if (!observing && ingame != -1) putstr("%Can't observe while playing"); else if (observing && ingame == atoi(first)) unobserve(); else if (observegame(atoi(first))) putstr("%No such game"); } } else if (!strcmp(first, "unobserve") || !strcmp(first, "unob")) { if (observing) unobserve(); else putstr("%Not observing"); } else if (!strcmp(first, "load")) { first = strtok(NULL, " \n\t"); if (first) loadgame(first); } else if (!strcmp(first, "chars")) { first = strtok(NULL, " \n\t"); if (first) { setchars(first); if (boardon) { reinitboard(boardsize); endgame(); } } } else if (!strcmp(first, "restore")) { if (!needrestore) putstr("%no game to restore"); restoregame(); } else if (!strcmp(first, "sort")) { first = strtok(NULL, " \t\n"); if (choosesort(first)) putstr("%Unknown sorting method"); } else if (!strcmp(first, "border")) { first = strtok(NULL, " \t"); if (!first) setborder(' '); else setborder(*first); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "inverse")) { setinverse(1); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "noinverse")) { setinverse(0); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "noinvedge")) { setinverseborder(0); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "noedgemarks")) { setedgemark(0); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "edgemarks")) { setedgemark(1); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "piecemarks")) { setpiecemark(1); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "nopiecemarks")) { setpiecemark(0); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "invedge")) { setinverseborder(1); if (boardon) { reinitboard(boardsize); endgame(); } } else if (!strcmp(first, "prefix")) { first = strtok(NULL, "\n"); if (!first) strcpy(prefix, ""); else { strncpy(prefix, first, 19); prefix[20] = 0; } if (boardon) showprefix(prefix); else printf("Prefix '%s'\n", prefix); } else if (!strcmp(first, "user")) { first = strtok(NULL, " \t\n"); { int i; int found; found = 0; for (i = 0; i < mesg.whocount; i++) { if (!strncmp(mesg.who[i] + NAMECOL, first, strlen(first)) && mesg.who[i][NAMECOL + strlen(first)] == ' ') { putstr(mesg.who[i]); found = 1; } } if (!found) putstr("User not found in last who"); } } else if (!strcmp(first, "saybeep")) saybeep = 1; else if (!strcmp(first, "nosaybeep")) saybeep = 0; else if (!strcmp(first, "tellbeep")) tellbeep = 1; else if (!strcmp(first, "notellbeep")) tellbeep = 0; else if (!strcmp(first, "beeps")) { first = strtok(NULL, " \t"); if (first) beepcount = atoi(first); } else if (!strcmp(first, "clear")) { if (!boardon) putstr("%Cannot clear."); else clearserver(); } else if (!strcmp(first, "noboard")) { if (boardon) { if (ingame != -1) { putstr("Board in use. Cannot remove."); } else { boardon = 0; boardmode = 0; endAscii(); } } else putstr("%No board to remove."); } else if (!strcmp(first, "goto")) { if (boardon) { first = strtok(NULL, " \t"); if (first) construct(atoi(first)); } else putstr("%no board"); } else { if (dopre) sendstr(prefix); sendstr(save); } } int notfirst = 0; doservermode(ch) char ch; { *loc = ch; *(loc + 1) = 0; if (ch < ' ' && ch != ('U' - 64) && ch != '\b' && ch != '\n') return; if (boardon) { if (*loc == '\b' || *loc == '\177') { if (strlen(local) > 1) { deletechar(strlen(local) - 2); loc -= 2; } else loc--; } else if (*loc == 'U' - 64) { loc = local; clrline(); return; } else if (strlen(local) > linesize()) { if (!notfirst) sendstr(prefix); sendstr(local); loc = local; notfirst = 1; clrline(); putstr(local); return; } else addcharline(strlen(local) - 1, *loc); } if (*loc == '\n') { loc++; *loc = 0; if (boardon) { addstring(local); } if (notfirst) sendstr(local); else if (local[0] == '!') process(local + 1, 0); else if (strlen(prefix)) { sendstr(prefix); sendstr(local); } else process(local, 1); if (boardon) clrline(); notfirst = 0; loc = local; } else loc++; } SHAR_EOF fi if test -f 'parse.c' then echo shar: "will not over-write existing file 'parse.c'" else cat << \SHAR_EOF > 'parse.c' #include "igc.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include "numbers.h" extern char *getloginname(); extern char *getpassword(); int loggedon; int repeatpass, repeatlogin; #ifdef STRSTR char *strstr(); #endif #ifdef STRTOL long strtol(); #endif char *Prompts[] = { "Login: ", "Password: ", "Password: ", "Enter Your Password Again: ", "Enter your e-mail address (None): ", "#> ", "#> ", "Enter Dead Group: ", "#> ", "#> ", }; initparser() { loggedon = 0; repeatpass = 0; repeatlogin = 0; } DoState(s) char *s; { if (strncmp(s, Prompts[LOGON], strlen(Prompts[LOGON])) == 0) return LOGON; if (strncmp(s, "1 1", 3) == 0) return PASSWORD; if (strncmp(s, "1 0", 3) == 0) return LOGON; if (strncmp(s, Prompts[PASSWORD], strlen(Prompts[PASSWORD])) == 0) return PASSWORD; if (strncmp(s, Prompts[PASSWD_NEW], strlen(Prompts[PASSWD_NEW])) == 0) return PASSWD_NEW; if (strncmp(s, Prompts[PASSWD_CONFIRM], strlen(Prompts[PASSWD_CONFIRM])) == 0) return PASSWD_CONFIRM; if (strncmp(s, Prompts[WAITING], strlen(Prompts[WAITING])) == 0) return WAITING; if (!strncmp(s, "Too many players, sorry", 23) || !strncmp(s, "Sorry, the server is full", 24)) return TOOMANY; return -1; } static long appending = 0; int getmessage(mess, checkstdin) message *mess; int checkstdin; { char mesg[2000]; int ret; char *textpart; ret = pollserver(mesg, checkstdin); if (ret <= 0) return ret; switch (DoState(mesg)) { case PASSWD_NEW: case PASSWD_CONFIRM: case PASSWORD: sendstr(getpassword(repeatpass++)); sendstr("\n"); break; case WAITING: sendstr("toggle client true\n"); mess->id = ONSERVER; loggedon = 1; return 1; case TOOMANY: mess->id = TOOMANY; return 1; case LOGON: { int needlogin; needlogin = 1; do { if (needlogin == 1) { sendstr(getloginname(repeatlogin++)); sendstr("\n"); needlogin = -1; } ret = pollserver(mesg, 0); if (ret < 0) return ret; if (!strncmp(mesg, "Password:", 9) || (!strncmp(mesg, "1 1", 3))) needlogin = 0; else if (!strncmp(mesg, "Sorry", 5)) { puts(mesg); if (!strncmp(mesg, "Sorry, the server is full", 24)) { mess->id = TOOMANY; return 1; } return 0; } else if (strlen(mesg) > 2 && strncmp(mesg, "Login", 5)) puts(mesg); } while (needlogin); sendstr(getpassword(repeatpass++)); sendstr("\n"); do { ret = pollserver(mesg, 0); if (ret < 0) return ret; if (!strncmp(mesg, "Enter", 5)) { sendstr(getpassword(repeatpass++)); sendstr("\n"); } if (!strncmp(mesg, "9 File", 6)) needlogin = -1; if (!strncmp(mesg, "To get", 6)) needlogin = 1; if (!strncmp(mesg, "#>", 2)) { sendstr("toggle client true\n"); mess->id = ONSERVER; loggedon = 1; return 1; } if (!strncmp(mesg, "Invalid", 7)) { puts(mesg); needlogin = 1; } } while (!needlogin); if (needlogin > 0) break; } /* intentional fall through occurs here */ default: mess->id = strtol(mesg, &textpart, 10); textpart++; if (mess->id == 2 && (strstr(textpart, "Game") || strstr(textpart, "min"))) mess->id = TIMEREP; if (appending == -1) { if (mess->id && !strncmp(textpart, "File", 4)) { appending = 0; if (mess->id == INFO && !strncmp(mess->text, "~~~~~~~~~~~~~~~~~~~~~", 21)) mess->id = QUITMESG; return 1; } if (strlen(mess->text)) { strcat(mess->text, "\n"); mess->lines++; } { int len; char *pt; len = strlen(mesg); pt = mesg; while (len > 0) { strncat(mess->text, pt, 79); len -= 79; pt += 79; if (len > 0) { mess->lines++; strcat(mess->text, "\n"); } } } return 0; } if (mess->id == PROMPT) { if (*textpart == '5' && !loggedon) loggedon = 1; if (appending) { mess->id = appending; appending = 0; return 1; } mess->prompttype = atoi(textpart); } if (!strcmp(textpart, "File")) { appending = -1; strcpy(mess->text, ""); mess->lines = 1; return 0; } if (mess->id == BEEP) { mess->beep = (*textpart == 7); } if (mess->id == KIBITZ) { if (parsekibitz(textpart, mess)) return 0; } if (mess->id == UNDO) if (ret = parseundo(textpart, &(mess->gamenum))) { if (ret < 0) return ret; return 0; } if (mess->id == TRANSLATE) { if (appending) { strcat(mess->text, "\n"); strcat(mess->text, textpart); mess->lines++; } else { strcpy(mess->text, textpart); mess->lines = 1; } appending = TRANSLATE; return 0; } if (mess->id == MOVE) { appending = MOVE; parsemove(textpart, mess); return 0; } if (mess->id == WHO) return parsewho(mess, textpart); if (mess->id == GAMES) { appending = GAMES; parsegame(mess, textpart); return 0; } if (mess->id == STATUS) return parsestatus(mess, textpart); strcpy(mess->text, textpart); mess->lines = 1; if (mess->id == ERROR && !strcmp("Game not found.", textpart)) { mess->id = GAMES; mess->gamecount = 0; return 1; } if (mess->id == INFO) if (ret = parseinfo(textpart, mess)) return ret; return 1; } return 0; } #ifdef STRTOL long strtol(text, new, dum) char *text; char **new; int dum; { long retu; retu = atol(text); for (*new = text; *new && **new <= '9' && **new >= '0'; (*new)++); return retu; } #endif #ifdef STRSTR char *strstr(s1, s2) char *s1, *s2; { register char *temp; int len; temp = s1; len = strlen(s2); while (temp = strchr(temp, *s2)) { if (!strncmp(temp, s2, len)) return temp; else temp++; } return NULL; } #endif int parsestatus(mesg, s) message *mesg; char *s; { int line, i; char wflag, bflag; if (1 == sscanf(s, " %d:", &line)) { mesg->boardsize = line + 1; for (i = 0, s += 4; *s; i++, s++) switch (*s) { case S_BLACK: mesg->board[line][i] = BLACK; break; case S_WHITE: mesg->board[line][i] = WHITE; break; case S_EMPTY: case S_HOSHI: mesg->board[line][i] = EMPTY; break; case S_WTERR: mesg->board[line][i] = WTERR; break; case S_BTERR: mesg->board[line][i] = BTERR; break; case S_DAME: mesg->board[line][i] = DAME; break; } if (i == line + 1) return 1; } else { if (mesg->wnext) { sscanf(s, "%[^ ] %[^ ] %d %d %d %c %f %d", mesg->white, mesg->wrank, &(mesg->wcap), &(mesg->wtime), &(mesg->wbyo), &wflag, &(mesg->mykomi), &(mesg->hcap)); if (wflag == 'F') mesg->wbyo = -1; } else { sscanf(s, "%[^ ] %[^ ] %d %d %d %c %f %d", mesg->black, mesg->brank, &(mesg->bcap), &(mesg->btime), &(mesg->bbyo), &bflag, &(mesg->mykomi), &(mesg->hcap)); if (bflag == 'F') mesg->bbyo = -1; } mesg->wnext = !mesg->wnext; } return 0; } int parsewho(mesg, str) message *mesg; char *str; { if (!strncmp(str, " Info", 5)) { mesg->whocount = 0; strcpy(mesg->text, str); mesg->lines = 1; strcpy(mesg->whofirst, str); } else { strcat(mesg->text, "\n"); strcat(mesg->text, str); mesg->lines++; if (strstr(str, "******")) { strcpy(mesg->wholast, str); return 1; } else { strncpy(mesg->who[mesg->whocount++], str, 34); if (strlen(str) > 40) strncpy(mesg->who[mesg->whocount++], str + 37, 34); } } return 0; } parsegame(mesg, str) message *mesg; char *str; { int fieldcount; char *br, *wr, blackrank[10], whiterank[10]; if (str[1] == '#') { mesg->gamecount = 0; strcpy(mesg->text, str); mesg->lines = 1; } else { strcat(mesg->text, "\n"); strcat(mesg->text, str); mesg->lines++; /* hacked for systems that don't like %[^]] */ for (br = str; *br; br++) if (*br == ']') *br = '!'; fieldcount = sscanf(str, "[%3d!%12s [%[^!]! vs.%12s [%[^!]! (%3d %d %d %f)\n", &(mesg->gamelist[mesg->gamecount].gnum), mesg->gamelist[mesg->gamecount].white, whiterank, mesg->gamelist[mesg->gamecount].black, blackrank, &(mesg->gamelist[mesg->gamecount].mnum), &(mesg->gamelist[mesg->gamecount].bsize), &(mesg->gamelist[mesg->gamecount].hcap), &(mesg->gamelist[mesg->gamecount].komi)); br = blackrank; wr = whiterank; if (*br == ' ') br++; if (*wr == ' ') wr++; strcpy(mesg->gamelist[mesg->gamecount].wrank, wr); strcpy(mesg->gamelist[mesg->gamecount].brank, br); if (fieldcount == 9) (mesg->gamecount)++; } } int parseinfo(s, mess) char *s; message *mess; { int ret; extern int boardsize; int row; char col; char text[100]; if (1 == sscanf(s, "Set the komi to %f.", &(mess->mykomi))) { mess->id = CHKOMI; return 0; } if (2 == sscanf(s, "Match [%dx%d]", &ret, &ret)) return 0; if (1 == sscanf(s, "Match [%d]", &(mess->gamenum))) { mess->id = MATCH; return 0; } if (1 == sscanf(s, "Creating match [%d]", &(mess->gamenum))) { mess->id = MATCH; return 0; } if (2 == sscanf(s, "Removing @ %c%d", &col, &row)) { if (col > 'I') col--; mess->x = col - 'A'; mess->y = boardsize - row; mess->id = REMOVE; return 0; } if (!strncmp(s, "Board is restored", 17)) { mess->id = SCOREUNDO; return 0; } if (strstr(s, "has restored your old game.")) { mess->id = LOAD; ret = pollserver(text, 0); if (ret < 0) return ret; ret = pollserver(text, 0); if (ret < 0) return ret; ret = sscanf(text, "%*d Game %d: %*[^(](%d %d %d) vs %*[^(](%d %d %d)", &(mess->gamenum), &(mess->bcap), &(mess->btime), &(mess->bbyo), &(mess->wcap), &(mess->wtime), &(mess->wbyo) ); ret = pollserver(text, 0); if (ret < 0) return ret; return 0; } return 0; } int parseundo(s, gamenum) char *s; int *gamenum; { char mes[2000]; int count; int bogus2, ret; char bogus1; count = sscanf(s, "%*[^ ] undid the last move (%c%d).", &bogus1, &bogus2); if (count == 2) { ret = pollserver(mes, 0); if (ret < 0) return ret; ret = pollserver(mes, 0); if (ret < 0) return ret; sscanf(mes, "%*d Game %d", gamenum); ret = pollserver(mes, 0); if (ret < 0) return ret; return 0; } if (1 == sscanf(s, "%*[^ ] undid the last move (Handicap %d).", &bogus2)) return 0; count = sscanf(s, "Undo in game %d", gamenum); if (count != 1) return 1; /* extra line */ return 0; } int parsekibitz(s, mess) char *s; message *mess; { if (1 == sscanf(s, "Kibitz %[^:]", mess->kibitzer)) return 1; while (*s == ' ') s++; strcpy(mess->kibitz, s); return 0; } parsemove(s, mess) char *s; message *mess; { int mc, y, mv; char c, col; extern int boardsize; if (!strncmp(s, "Game ", 5)) { sscanf(s, "Game %d: %*[^(](%d %d %d) vs %*[^(](%d %d %d)", &(mess->gamenum), &(mess->wcap), &(mess->wtime), &(mess->wbyo), &(mess->bcap), &(mess->btime), &(mess->bbyo)); mess->movecount = 0; return; } mc = sscanf(s, "%3d(%c): %c%d", &mv, &c, &col, &y); if (mc == 3) { if (3 == sscanf(s, "%3d(%c): Handicap %d", &mv, &c, &mc)) { mess->moves[mess->movecount].x = mess->moves[mess->movecount].y = mc + 100; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; return; } if (2 == sscanf(s, "%3d(%c): Pass", &mv, &c)) { mess->moves[mess->movecount].x = mess->moves[mess->movecount].y = 99; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; return; } } if (col > 'I') col--; mess->moves[mess->movecount].x = col - 'A'; mess->moves[mess->movecount].y = boardsize - y; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; } int doneline(inbuf, inptr) char *inbuf; int inptr; { return !loggedon && (inptr > 0 && inbuf[inptr - 1] == ' ') && ((inptr > 1 && inbuf[inptr - 2] == ':') || (inptr > 2 && inbuf[inptr - 2] == '>' && inbuf[inptr - 3] == '#')); } SHAR_EOF fi if test -f 'ascii.c' then echo shar: "will not over-write existing file 'ascii.c'" else cat << \SHAR_EOF > 'ascii.c' #include <curses.h> #define piece char #define TOP 2 #define LEFT 3 #define RIGHT 79 #define min(a,b) (((a)<(b))?(a):(b)) #define TITLEX 6 #define HIGHLIGHT 23 #define CHAR_NOTHING 0 #define CHAR_BLACK 1 #define CHAR_WHITE 2 #define CHAR_DAME 3 #define CHAR_BLACKTERR 4 #define CHAR_WHITETERR 5 #define CHAR_HANDICAP 6 #define CHAR_VERT 7 #define ASC_NUMCHARS 8 WINDOW *boardwin, *serverwin, *iowin; char xAxisChars[] = "ABCDEFGHJKLMNOPQRST"; int inverseFlag = 1; int inverseBorder = 0; int lastwin = 1; int boardsize = -1; char chars[] = ".#O?+-+ "; int servecols = -1; static int init = 0; int endw = -1, endb = -1; int reinit = 0; int doedgemarkers = 0; int dopiecemarkers = 1; setedgemark(mark) int mark; { doedgemarkers = mark; } setpiecemark(mark) int mark; { dopiecemarkers = mark; } setinverse(inv) int inv; { inverseFlag = inv; } setinverseborder(inv) int inv; { inverseBorder = inv; } setborder(ch) char ch; { chars[CHAR_VERT] = ch; } setchars(s) char *s; { int i; for (i = 0; i <= min(CHAR_VERT, strlen(s) - 1); i++) chars[i] = s[i]; } serverrefresh() { if (lastwin) wrefresh(iowin); else wrefresh(serverwin); } boardrefresh() { wrefresh(boardwin); } void initAscii() { if (!init) { init = 1; initscr(); noecho(); crmode(); } } suspend() { move(23, 0); refresh(); echo(); nocrmode(); } redraw() { clearok(stdscr, TRUE); refresh(); clearok(stdscr, FALSE); } unsuspend() { noecho(); crmode(); redraw(); } displaygamenumber(n) int n; { move(0, 0); if (n >= 0) printw("%3d", n); else if (n == -1) printw("-- "); else printw("sta"); refresh(); } boardtitle(bs, ws) char *bs, *ws; { int i; move(0, TITLEX); for (i = 0; i < 35; i++) addch(' '); move(1, TITLEX); for (i = 0; i < 35; i++) addch(' '); if (strlen(bs)) { move(0, TITLEX); printw("Black: %s", bs); endb = TITLEX + 8 + strlen(bs); move(1, TITLEX); printw("White: %s", ws); endw = TITLEX + 8 + strlen(ws); } refresh(); } static void sbinverse() { if (inverseBorder) wstandout(boardwin); } static void set_inverse() { if (inverseFlag) wstandout(boardwin); } static void unset_inverse() { wstandend(boardwin); } setcursor(x, y) int x, y; { wmove(boardwin, TOP + y, LEFT + 2 * x); wrefresh(boardwin); } void drawPiece(i, j, c) int i, j; char c; { wmove(boardwin, TOP + j, LEFT + 2 * i); set_inverse(); waddch(boardwin, c); unset_inverse(); } void deleteBoardAscii() { delwin(boardwin); delwin(serverwin); delwin(iowin); } void endAscii() { init = 0; deleteBoardAscii(); boardsize = -1; clear(); refresh(); echo(); nocrmode(); endwin(); } char boardPiece(x, y, boardsize) int x, y, boardsize; { return (((boardsize == 19 && x == 9) || (boardsize >= 10 && (x == 3 || x == boardsize - 4)) || (boardsize > 6 && boardsize < 10 && (x == 2 || x == boardsize - 3))) && ((boardsize == 19 && y == 9) || (boardsize >= 10 && (y == 3 || y == boardsize - 4)) || (boardsize > 6 && boardsize < 10 && (y == 2 || y == boardsize - 3)))) ? chars[(int) CHAR_HANDICAP] : chars[(int) CHAR_NOTHING]; } drawOneStone(i, j, t) int i, j; piece t; { if (t == 0) drawPiece(i, j, boardPiece(i, j, boardsize)); else drawPiece(i, j, chars[t]); wrefresh(boardwin); } drawStone(i, j, t) int i, j; piece t; { if (t == 0) drawPiece(i, j, boardPiece(i, j, boardsize)); else drawPiece(i, j, chars[t]); } unmarkascii(i, j) int i, j; { if (!init) return; if (i >= 0 && i <= 19) { set_inverse(); if (dopiecemarkers) { wmove(boardwin, TOP + j, LEFT + 2 * i - 1); waddch(boardwin, ' '); wmove(boardwin, TOP + j, LEFT + 2 * i + 1); waddch(boardwin, ' '); } if (doedgemarkers) { wmove(boardwin, TOP + j, LEFT - 1); waddch(boardwin, chars[CHAR_VERT]); wmove(boardwin, TOP + j, LEFT + boardsize * 2 - 1); waddch(boardwin, chars[CHAR_VERT]); unset_inverse(); sbinverse(); wmove(boardwin, TOP - 1, LEFT + i * 2); waddch(boardwin, xAxisChars[i]); wmove(boardwin, TOP + boardsize, LEFT + i * 2); waddch(boardwin, xAxisChars[i]); } unset_inverse(); } } unhighlight(i, j) int i, j; { int k; if (!init) return; move(HIGHLIGHT, 0); for (k = 1; k < 80 - servecols; k++) addch(' '); move(0, TITLEX - 2); printw(" "); move(1, TITLEX - 2); printw(" "); unmarkascii(i, j); } static char *who[] = {"Black", "White"}; showhcap(hcap) int hcap; { if (!init) return; move(0, LEFT + 19 * 2 + 1); if (hcap) printw("%d", hcap); else addch(' '); refresh(); } showkomi(komi) float komi; { if (!init) return; move(1, LEFT + 19 * 2 - 1); printw("%1.1f", komi); refresh(); } highlight(i, j, num, t, btime, bbyo, wtime, wbyo) int i, j; piece t; int btime, bbyo, wtime, wbyo; { int k; if (btime != -1) { move(0, endb); if (btime < 0) btime = 0; if (wtime < 0) wtime = 0; printw("%d:%02d", btime / 60, btime % 60); if (bbyo != -1) printw(", %d", bbyo); addstr(" "); move(1, endw); printw("%d:%02d", wtime / 60, wtime % 60); if (wbyo != -1) printw(", %d", wbyo); addstr(" "); } if (t >= 0) { move(t == 1 ? 1 : 0, TITLEX - 2); printw("->"); } move(HIGHLIGHT, 0); for (k = 1; k < 80 - servecols; k++) addch(' '); if (i == 99) { move(HIGHLIGHT, 0); printw("%s #%d Pass", who[t - 1], num); } else if (i < 100 && num) { move(HIGHLIGHT, 0); printw("%s #%d at %c%d", who[t - 1], num, i + 'A' + (i + 'A' >= 'I' ? 1 : 0), boardsize - j); set_inverse(); if (dopiecemarkers) { wmove(boardwin, TOP + j, LEFT + 2 * i - 1); waddch(boardwin, '>'); wmove(boardwin, TOP + j, LEFT + 2 * i + 1); waddch(boardwin, '<'); } if (doedgemarkers) { wmove(boardwin, TOP + j, LEFT - 1); waddch(boardwin, '>'); wmove(boardwin, TOP + j, LEFT + boardsize * 2 - 1); waddch(boardwin, '<'); unset_inverse(); sbinverse(); wmove(boardwin, TOP - 1, LEFT + i * 2); waddch(boardwin, '!'); wmove(boardwin, TOP + boardsize, LEFT + i * 2); waddch(boardwin, '!'); } unset_inverse(); } } drawpris(pris) int *pris; { move(23, 22); printw("Captured %c: %d %c: %d ", chars[CHAR_BLACK], *pris, chars[CHAR_WHITE], pris[1]); refresh(); } void initBoardAscii(size) int size; { int i, j; if (!reinit) { if (size == boardsize) { for (i = boardsize; i--;) for (j = boardsize; j--;) drawStone(i, j, 0); return; } if (boardsize != -1) deleteBoardAscii(); boardsize = size; clear(); boardwin = subwin(stdscr, boardsize + 4, boardsize * 2 - 1 + 6 + 2, 1, 0); servecols = COLS - 19 * 2 - 6 - 2; serverwin = subwin(stdscr, 22, servecols, 0, 19 * 2 - 1 + 6 + 2); iowin = subwin(stdscr, 2, servecols, 22, 19 * 2 - 1 + 6 + 2); } if (inverseFlag || reinit) { set_inverse(); for (i = LEFT + 1; i < LEFT + boardsize * 2 - 2; i += 2) for (j = TOP; j < TOP + boardsize; j++) mvwaddch(boardwin, j, i, ' '); unset_inverse(); } for (i = boardsize; i--;) { /* left */ wmove(boardwin, TOP + i, LEFT - 3); sbinverse(); wprintw(boardwin, "%2d", boardsize - i); unset_inverse(); set_inverse(); waddch(boardwin, chars[(int) CHAR_VERT]); /* right */ wmove(boardwin, TOP + i, LEFT + boardsize * 2 - 1); waddch(boardwin, chars[(int) CHAR_VERT]); unset_inverse(); sbinverse(); wprintw(boardwin, "%2d", boardsize - i); unset_inverse(); waddch(boardwin, chars[(int) CHAR_VERT]); /* top */ wmove(boardwin, TOP - 1, LEFT + i * 2); sbinverse(); waddch(boardwin, xAxisChars[i]); waddch(boardwin, ' '); unset_inverse(); wmove(boardwin, TOP - 1, LEFT + i * 2 - 1); set_inverse(); /* bottom */ wmove(boardwin, TOP + boardsize, LEFT + i * 2 - 1); unset_inverse(); wmove(boardwin, TOP + boardsize, LEFT + i * 2); sbinverse(); waddch(boardwin, xAxisChars[i]); waddch(boardwin, ' '); unset_inverse(); for (j = boardsize; j--;) drawStone(i, j, 0); } sbinverse(); wmove(boardwin, TOP - 1, LEFT - 3); waddstr(boardwin, " "); wmove(boardwin, TOP + boardsize, LEFT - 3); waddstr(boardwin, " "); wmove(boardwin, TOP - 1, LEFT + 2 * boardsize); waddstr(boardwin, " "); wmove(boardwin, TOP + boardsize, LEFT + 2 * boardsize); waddstr(boardwin, " "); unset_inverse(); wmove(boardwin, size / 2, size / 2); } reinitboardascii() { reinit = 1; initBoardAscii(boardsize); reinit = 0; } clearserver() { wclear(serverwin); wrefresh(serverwin); } addcharline(pos, ch) int pos; char ch; { wmove(iowin, 1, pos); waddch(iowin, ch); wrefresh(iowin); lastwin = 1; } deletechar(pos) int pos; { wmove(iowin, 1, pos); waddch(iowin, ' '); wmove(iowin, 1, pos); wrefresh(iowin); lastwin = 1; } int linesize() { return servecols - 2; } clrline() { wmove(iowin, 1, 0); wclrtoeol(iowin); wrefresh(iowin); } addchar(ch) char ch; { int x, y, maxx, maxy; if (ch == '\r') return; waddch(serverwin, ch); maxy = serverwin->_maxy - 1; /* 20 */ maxx = serverwin->_maxx - 1; /* servecols - 1; */ getyx(serverwin, y, x); if ((x == maxx - 1 && y == maxy) || (ch == '\n' && y == maxy) || y > maxy) { wmove(serverwin, 0, 0); wclrtoeol(serverwin); } else if (x == 0 && y <= maxy) { wclrtoeol(serverwin); wmove(serverwin, y + 1, 0); wclrtoeol(serverwin); wmove(serverwin, y, x); } wrefresh(serverwin); lastwin = 0; } showprefix(s) char *s; { wmove(iowin, 0, 0); wclrtoeol(iowin); if (strlen(s)) wprintw(iowin, "Prefix: '%s'", s); wrefresh(iowin); } /* addstring(s) char *s; { char *p; for (p = s; *p; p++) addchar(*p); } */ void addstring(s) /* add a string of chars to server win */ char *s; { char *p, *q; char word[64]; int count; /* parse a word. if it doesn't wrap, addchar it */ /* if it does then addchar a \n and then word */ count = 0; p = s; while (*p) { q = word; while (*p != ' ' && *p != '\n' && *p != '\0') { *q = *p; q++; p++; } *q = *p; q++; if (*p) p++; *q = '\0'; if (count + strlen(word) > 32) { addchar('\n'); count = 0; } count += strlen(word); count %= 33; if (p[-1] == '\n') count = 0; for (q = word; *q; q++) addchar(*q); } } bigmess(lines, intext) int lines; char *intext; { WINDOW *savescr; char ch; int i, count; int rest; char *mynl, *localcopy, *text; text = localcopy = (char *) malloc(strlen(intext) + 1); strcpy(text, intext); mynl = ""; if (lines > 22) { rest = lines; lines = 22; } else rest = 0; savescr = newwin(24, 80, 0, 0); overwrite(stdscr, savescr); do { if (rest > 0) { for (mynl = text, count = 22; count && *mynl; mynl++) if (*mynl == '\n') count--; *(mynl - 1) = 0; rest -= 22; } for (i = (24 - lines) / 2 - 1; i < (24 - lines) / 2 + lines + 1; i++) { move(i, 0); clrtoeol(); } move((24 - lines) / 2, 0); addstr(text); refresh(); while (read(0, &ch, 1) != 1); text = mynl; } while (rest > 0); overwrite(savescr, stdscr); refresh(); delwin(savescr); free(localcopy); } SHAR_EOF fi if test -f 'board.c' then echo shar: "will not over-write existing file 'board.c'" else cat << \SHAR_EOF > 'board.c' #include "igc.h" typedef char boardtype[19][19]; int prisoners[2]; int movenum, maxmove; typedef struct { int x, y; char col; } movelist[500]; movelist moves; boardtype board; #define boolean char #define false 0 #define true 1 static int boardsize = -1; int lasti = -1, lastj = -1; clearboard(b, pris) boardtype b; int *pris; { int i, j; pris[0] = pris[1] = 0; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) b[i][j] = EMPTY; } initboard(size) int size; { clearboard(board, prisoners); unhighlight(lasti, lastj); showhcap(0); initAscii(); initBoardAscii(size); boardsize = size; maxmove = movenum = 0; } reinitboard(size) int size; { unhighlight(lasti, lastj); showhcap(0); clearboard(board, prisoners); initAscii(); reinitboardascii(); boardsize = size; } boolean inRange(i, j) { return i >= 0 && i < boardsize && j >= 0 && j < boardsize; } boolean alive0(b, m, i, j, t) boardtype b; boardtype m; int i, j; piece t; { piece pt; pt = b[i][j]; if ((pt != EMPTY && pt != t) || m[i][j] != EMPTY) return 0; m[i][j] = (pt == t) ? (piece) 1 : (piece) 2; if (pt == EMPTY) return 1; return (j < boardsize - 1 && alive0(b, m, i, j + 1, t)) || (i < boardsize - 1 && alive0(b, m, i + 1, j, t)) || (i && alive0(b, m, i - 1, j, t)) || (j && alive0(b, m, i, j - 1, t)); } boolean alive(b, i, j) /* Does group at i,j have liberties? */ boardtype b; int i, j; { boardtype m; int p[2]; clearboard(m, p); return alive0(b, m, i, j, b[i][j]); } int removed; int dontdraw = 0; void removeStones0(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { if (b[i][j] != t) return; b[i][j] = EMPTY; if (!dontdraw) drawStone(i, j, 0); removed = 1; pris[t - 1]++; if (j < boardsize - 1) removeStones0(b, pris, i, j + 1, t); if (i < boardsize - 1) removeStones0(b, pris, i + 1, j, t); if (i) removeStones0(b, pris, i - 1, j, t); if (j) removeStones0(b, pris, i, j - 1, t); } void removeStones(b, pris, i, j) boardtype b; int *pris; int i, j; { removed = 0; removeStones0(b, pris, i, j, b[i][j]); /* if (removed) boardrefresh(); */ } void removeGroup(i, j) int i, j; { removeStones(board, prisoners, i, j); } boolean tryKill(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { piece w; if (!inRange(i, j)) return false; w = b[i][j]; if (w != EMPTY && w != t && !alive(b, i, j)) { removeStones(b, pris, i, j); return true; } return false; } void placeStone(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { if (inRange(i, j)) { b[i][j] = t; if (j) tryKill(b, pris, i, j - 1, t); if (j < boardsize - 1) tryKill(b, pris, i, j + 1, t); if (i) tryKill(b, pris, i - 1, j, t); if (i < boardsize - 1) tryKill(b, pris, i + 1, j, t); } } static highlighting = 1; makemove(i, j, num, t, btime, bbyo, wtime, wbyo) int i, j; piece t; int btime, bbyo, wtime, wbyo; { if (movenum != maxmove) { construct(maxmove); } if (highlighting) unhighlight(lasti, lastj); if (num == 1 && i <= 19) showhcap(0); if (i > 100) { sethandicap(board, i - 100); showhcap(i - 100); moves[num].x = moves[num].y = i; moves[num].col = t; maxmove = movenum = num; if (highlighting) highlight(i, j, num, t, btime, bbyo, wtime, wbyo); return; } if (i == 99) { moves[num].x = moves[num].y = 99; moves[num].col = t; maxmove = movenum = num; if (highlighting) { highlight(i, j, num, t, btime, bbyo, wtime, wbyo); drawpris(prisoners); } return; } placeStone(board, prisoners, i, j, t); if (highlighting) highlight(i, j, num, t, btime, bbyo, wtime, wbyo); if (highlighting) drawpris(prisoners); if (highlighting) drawOneStone(i, j, t); else drawStone(i, j, t); lasti = i; lastj = j; moves[num].x = i; moves[num].y = j; moves[num].col = t; maxmove = movenum = num; } unmark() { unmarkascii(lasti, lastj); } construct(mov) int mov; { int i, j; boardtype myboard; int mypris[2]; if (mov > maxmove) mov = maxmove; if (mov < 1) mov = 1; clearboard(myboard, mypris); unhighlight(lasti, lastj); dontdraw = 1; for (i = 1; i <= mov; i++) { if (moves[i].x > 100) sethandicap(myboard, moves[i].x - 100); else if (moves[i].x != 99) { placeStone(myboard, mypris, moves[i].x, moves[i].y, moves[i].col); myboard[moves[i].x][moves[i].y] = moves[i].col; } } dontdraw = 0; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != myboard[i][j]) { drawStone(i, j, myboard[i][j]); board[i][j] = myboard[i][j]; } prisoners[0] = mypris[0]; prisoners[1] = mypris[1]; highlight(moves[mov].x, moves[mov].y, mov, moves[mov].col, -1, -1, -1, -1); lasti = moves[mov].x; lastj = moves[mov].y; drawpris(prisoners); movenum = mov; } int savemaxmove = 0, didsave = 0; restoremaxmoves() { didsave = 0; maxmove = savemaxmove; } savemaxmoves() { if (!didsave) { didsave = 1; savemaxmove = maxmove; } } showboard(b) boardtype b; { int i, j; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != b[i][j]) { drawStone(i, j, b[i][j]); board[i][j] = b[i][j]; } boardrefresh(); } undo() { int i, j; maxmove--; if (maxmove) construct(maxmove); else { movenum = 0; unhighlight(lasti, lastj); for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != EMPTY) { drawStone(i, j, EMPTY); board[i][j] = EMPTY; } } } int forward(num) int num; { if (!maxmove) return 1; if (movenum < maxmove) construct(movenum + num); /* construct() does bounds checking */ return 0; } int backward(num) int num; { if (!maxmove) return 1; if (movenum > 1) construct(movenum - num); /* construct() does bounds checking */ return 0; } int beginninggame() { if (!maxmove) return 1; construct(1); return 0; } int endgame() { if (!maxmove) return 1; construct(maxmove); return 0; } sethighlight(h) int h; { highlighting = h; } #define TOP 0 #define MID 1 #define BOT 2 static int verts[3][26] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 4}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 0, 0, 9, 0, 10, 0, 0, 0, 12}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 17, 0, 0, 0, 20}, }; sethandicap(board, hand) boardtype board; int hand; { /* This is also used to set the handicap. The 'handi' is the number of * things to set of piece 'p'. */ int top, mid, bot; piece t; top = verts[TOP][boardsize]; mid = verts[MID][boardsize]; bot = verts[BOT][boardsize]; /* All of these drop through, '5' checks for odd points. */ t = 1; switch (hand) { case 9: /* taken care of by handi == 5 */ case 8: drawStone(mid, top, t); board[mid][top] = t; drawStone(mid, bot, t); board[mid][bot] = t; case 7: /* taken care of by handi == 5 */ case 6: drawStone(bot, mid, t); board[bot][mid] = t; drawStone(top, mid, t); board[top][mid] = t; case 5: if (hand & 0x1) { /* odd points, test because of drop through */ drawStone(mid, mid, t); board[mid][mid] = t; } case 4: drawStone(bot, bot, t); board[bot][bot] = t; case 3: drawStone(top, top, t); board[top][top] = t; case 2: drawStone(bot, top, t); board[bot][top] = t; drawStone(top, bot, t); board[top][bot] = t; break; default: break; } } SHAR_EOF fi if test -f 'numbers.h' then echo shar: "will not over-write existing file 'numbers.h'" else cat << \SHAR_EOF > 'numbers.h' typedef enum { UNKNOWN = 0, BEEP = 2, /* \7 telnet */ BOARD = 3, /* Board being drawn */ DOWN = 4, /* The server is going down */ ERROR = 5, /* An error reported */ FIL = 6, /* File being sent */ GAMES = 7, /* Games listing */ HELP = 8, /* Help file */ INFO = 9, /* Generic info */ LAST = 10, /* Last command */ KIBITZ = 11, /* Kibitz strings */ LOAD = 12, /* Loading a game */ LOOK = 13, /* Look */ MESSAGE = 14, /* Message lising */ MOVE = 15, /* Move #:(B) A1 */ OBSERVE = 16, /* Observe report */ PROMPT = 1, /* A Prompt (never) */ REFRESH = 17, /* Refresh of a board */ SAVED = 18, /* Stored command */ SAY = 19, /* Say string */ SCORE = 20, /* Score report */ SHOUT = 21, /* Shout string */ STATUS = 22, /* Current Game status */ STORED = 23, /* Stored games */ TELL = 24, /* Tell string */ THIST = 25, /* Thist report */ TIM = 26, /* times command */ WHO = 27, /* who command */ UNDO = 28, /* Undo report */ TRANSLATE = 30 } MessageType; #define S_BLACK '0' #define S_WHITE '1' #define S_EMPTY '2' #define S_DAME '3' #define S_WTERR '4' #define S_BTERR '5' #define S_HOSHI '6' #define LOGON 0 #define PASSWORD 1 #define PASSWD_NEW 2 #define PASSWD_CONFIRM 3 #define REGISTER 4 #define WAITING 5 #define PLAYING 6 #define SCORING 7 #define OBSERVING 8 SHAR_EOF fi if test -f 'igc.h' then echo shar: "will not over-write existing file 'igc.h'" else cat << \SHAR_EOF > 'igc.h' #define MAXGAMES 20 #define MAXWHO 300 #define MAXNAME 11 #define MAXRANK 6 #define piece char #ifdef BCOPY #define bcopy(a,b,c) memcpy(b,a,c) #endif typedef struct { int id; int prompttype; /* if return is prompt */ int x, y; /* used to report removed stones for scoring */ struct { /* if return is play */ int x, y; int movenum; int color; } moves[400]; int movecount; int gamenum; int bcap, btime, bbyo; int wcap, wtime, wbyo; char text[10000]; /* text of message */ int lines; /* number of lines in text */ int gamecount; /* for data from the games command */ struct { int gnum; char white[MAXNAME], wrank[MAXRANK], black[MAXNAME], brank[MAXRANK]; int mnum, bsize, hcap; float komi; } gamelist[MAXGAMES]; int boardsize, boardline; float wscore, bscore; piece board[19][19]; int wnext; /* white next? Already have info for black. */ char white[MAXNAME], wrank[MAXRANK], black[MAXNAME], brank[MAXRANK]; int hcap; int beep; char kibitzer[40]; char kibitz[300]; char whocount; char *who[MAXWHO]; char whodata[MAXWHO][40]; char wholast[80]; char whofirst[80]; float mykomi; } message; #define ONSERVER -1 #define MATCH -2 #define QUITMESG -3 #define REMOVE -4 #define SCOREUNDO -5 #define TIMEREP -6 #define TOOMANY -7 #define CHKOMI -8 #define BLACK 1 #define WHITE 2 #define EMPTY 0 #define DAME 3 #define BTERR 4 #define WTERR 5 #define KEY -33 SHAR_EOF fi if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' CC = cc # if you get strstr undefined, add -DSTRSTR to the DEFINES line below # if you get bcopy undefined, add -DBCOPY # if you get strtol undefined, add -DSTRTOL # if you change something in the Makefile, you may need to # type rm *.o before trying to recompile. # The -DDEBUG below causes igc to create dump?.igc files which # contain logs of each IGS session. Remove the -DDEBUG # to suppress creation of the dump files. I may request # the log files from you if you report bugs. DEFINES = -DDEBUG # You may want to change -g (include debug information) into # -O for optimize. If you do this, also run strip on the # igc file: 'strip igc'. This will make the executable # even smaller. CFLAGS = -g $(DEFINES) LIBS = -lcurses -ltermlib # link line for PTX. System V systems need something like this: #LIBS = -lcurses -ltermlib -lsocket -linet -lnsl # Under Irix running Yellow Pages, add -lsun to the link line # Under RS/6000 AIX 3.1, remove the -ltermlib PROGRAM = igc MAN = igc.doc OBJ = socket.o igc.o parse.o ascii.o board.o SRC = socket.c igc.c parse.c ascii.c board.c HDRS = numbers.h igc.h FILES = README $(SRC) $(HDRS) Makefile igc.6 all: $(PROGRAM) $(MAN) $(PROGRAM): $(OBJ) @echo Loading... @$(CC) $(OBJ) $(LIBS) -o $(PROGRAM) $(MAN): igc.6 nroff -man igc.6 > $(MAN) $(OBJ): $(HDRS) shar: @shar $(FILES) > $(PROGRAM).shar shar2: @shar -m 200000 -f $(PROGRAM) $(FILES) lint: lint $(SRC) -lcurses > lintout SHAR_EOF fi if test -f 'igc.6' then echo shar: "will not over-write existing file 'igc.6'" else cat << \SHAR_EOF > 'igc.6' .TH IGC 6 "9 September 1992" .SH NAME igc - ascii client to Internet Go Server .SH SYNOPSIS .B igc [\-s] [host [port]] .SH DESCRIPTION Go is an ancient asian strategy game based on the capture of territory. Players alternate, placing stones on the board and trying to surround as many empty intersections as possible. The .B Internet Go Server allows players to meet and play interactive games. .B Igc provides a more convenient interface for connections to the .B Internet Go Server. .SH COMMAND LINE OPTIONS .TP 8 .B \-s Supresses autologin. .LP .TP 8 .B [host [port]] Connects to specified host and port number. The host can be specified as a fully qualified hostname, or as an abbreviation. If the abbreviation is used, then the port number cannot be included. The shorthand names supported by default are: .in +2m .ta .ta 7m +\w'mmmmm\ \ 'u +\w'icsib18.icsi.berkeley.edu\ \ 'u + .nf name host address port site0 icsi icsib18.icsi.berkeley.edu 6969 site1 cnam cnam.cnam.fr 6969 .nf .in -2m If no host is specified, then site0 is used. To connect to the French site, for example, use 'igc cnam'. (See the customization section for more information.) .SH OPERATION When .B igc is run, it opens a connection to the go server. Unlike a straight telnet connection, .B igc does not print the '#>' prompt, and your normal suspend key (usually ^Z) will suspend the client. If you use telnet after using .B igc the prompts from the server will be different because the server is in client mode. Log in with username and password at the numeric prompts and then type 'toggle client' to get the normal prompts. .LP Initially, .B igc acts as a direct connection to the server. When a game is displayed, the screen will be split into two windows: one for the board on the left, and one for text interaction with the server on the right. The ESC key will switch between the two windows, and the ^L key will redraw the display (from either window). .LP When the server sends long messages such as the output from the 'games' command, the 'who' command, or the 'help' commmand, it prints the message on top of the board. Press any key to restore the board. If the message is longer than 22 lines, then the message will be displayed in chunks. .LP The names of the players appear above the board, followed by their ranks, and the time remaining. An arrow indicates whose turn it is. You can view only one game at a time (either by observing, or by playing). The number of that game is displayed to the left of the Black's name. This number should be '--' if you are not playing or observing a game. To the right of Black's name, above the right corner of the board (in 19x19 games), is the number of handicap stones. This region is blank if the game is even. To the right of white's name is the komi for the game. Below the board, a line shows the number and coordinates of the last move, and the captured stones are displayed. The display shows the number of black stones which were captured, followed by the number of white stones captured. .LP All of the commands which are active from the board window are single keystroke commands. The cursor can be moved around the board using either the number keys (12346789), the emacs keys (^P ^N ^B ^F) or the rogue keys (hjklyubn). The board keeps track of all moves received so that you can view the history of the game. Note that the server's 'look' and 'status' commands do not generate a move history. When these commands are used, or when a game is scored, a snapshot of the board is obtained from the server and temporarily placed on top of the board. The receipt of a move, or any attempt to move through the game record, will restore the previous display. When the status display is active, the game number area in the upper right corner of the screen reads "sta". The previous display can be restored by the client command 'restore'. .LP .TP 8 0, space, return Makes a move on the board. (Send the coordinates of the cursor to the server.) .LP .TP 8 c Clears the marks on the board which indicate which piece was played last. .LP .TP 8 comma, period (, and .) Move backwards (comma) or forwards (period) through the moves in the game currently displayed on the board. If a new move arrives while you are observing the game like this, you will be bounced back to the end of the game. .LP .TP 8 <, > Move backwards or forwards by sets of ten moves through the game currently displayed on the board. .LP .TP 8 s, e Jump to start (s) or end (e) of the game displayed on the board. .LP Commands in the server window are words rather than single characters. These commands will work in the full screen mode as well when appropriate. The backspace and delete keys will remove the last character you typed, and ^U will kill the whole line. .LP .TP 4 helpigc Display a brief help screen. .LP .TP 4 observe <n> Begin observing game n. If you are already observing a game, this command will stop observing that game and begin observing game n. If you are observing game n, then this command will stop observing game n. This command can be abbreviated as 'ob'. .LP .TP 4 unobserve Stop observing the game you are watching. This command can be abbreviated as 'unob'. .LP .TP 4 peek <n> Peeks at game n. Fetches all the moves from that game without observing so that you can play the game back from the start, or just see what it looks like. .LP .TP 4 restore Restores the active game display which was on the board before a 'look' or 'status' command. This command is only valid when the upper left corner of the screen says "sta". .LP .TP 4 goto <n> Goes to move n in the game displayed on the board. .LP .TP 4 clear Clears the server window .LP .TP 4 noboard Removes the board and returns to full screen interaction with the server. .LP .TP 4 user <name> Prints the line for <name> from the output of the last who command. .LP .TP 4 sort <sort-type> Sets the sorting method for output from the server's 'who' command. Available sorting methods are: none, rank, name, and game. The 'none' type does no sorting. The 'name' type sorts by name, 'rank' sorts by rank, 'idle' sorts by idle time and 'game' sorts first by the game a player is playing in, second by whether a player is open for games, and finally by rank. The default sorting method is 'name'. .LP .TP4 inverse Switch board display to inverse video. (This is the default display). .LP .TP 4 noinverse Switch board display to regular video. .LP .TP 4 invedge Display edges with inverse video. .LP .TP 4 noinvedge Display edges with normal video. (This is the default). .LP .TP 4 chars <list> Sets the board characters. The order is empty, black, white, dame, black territory, white territory, hoshi point, border. The characters should appear without spaces betwee them. The default character set is .#O?+-+ with a space for the border character. .LP .TP 4 border <char> Sets the border character to char. If char is omitted then the border is turned off. (This is the default.) .LP .TP 4 beeps <n> Sets the number of beeps sent when sending a beep. The default is one. .LP .TP 4 saybeep Causes .B igc to beep when your opponent says something to you during a game using the say command. Does not cause messages sent with the tell command to beep. .LP .TP 4 nosaybeep Do not beep when your opponent says something to you with the say command. (This is the default.) .LP .TP 4 tellbeep Causes .B igc to beep if anyone tells you anything at any time. Does not cause messages sent with the say command to beep. .LP .TP 4 notellbeep Do not beep when people tell things to you. (This is the default.) .LP .TP 4 prefix <text> Adds text to every line you type to the server. All characters before your text will be used in the prefix. The purpose of this command is to make it easier to hold conversations with someone. To talk with goplayer, you might type 'prefix tell goplayer ' (note the extra space). All subsequent lines would be sent to goplayer. If you start a line with '!' then the prefix will not be used. To turn off the prefix, type '!prefix'. When the prefix is active and the board is displayed, the prefix text is displayed at the bottom of the server window. .LP .TP 4 edgemarks Turns on display of marks at the edge of the board to indicate last move. .LP .TP 4 noedgemarks Turns off display of marks at the edge of the board to indicate last move. (This is the default.) .LP .TP 4 piecemarks Turns on display of marks around the last stone played. (This is the default.) .LP .TP 4 nopiecemarks Turns off display of marks around the last stone played. .SH CUSTOMIZATION The file .B .igcrc is used to do initialization. You do not need to have this file, but it can set up .B igc to suit your desires and it can automatically log you in. You create this file in your home directory yourself, using a text editor (emacs, vi). The following server window commands are supported in the .B .igcrc file: inverse, noinverse, invedge, noinvedge, beeps, saybeep, nosaybeep, chars, border, sort. They can be used to configure the display as desired. .LP Some special commands are supported as well: .LP .TP 4 login <name> Causes .B igc to automatically send <name> as your login name when the connection is established. (This is suppressed by the \-s option.) .LP .TP 4 password <password> Causes .B igc to send <password> as your password. If you use this command, you should make sure that your .B .igcrc file is not world readable. Use the command 'chmod 600 .igcrc' to set the insure that this file is not world readable. (Transmission of <password> is supressed by the \-s option.) .LP .TP 4 site# <name> <address> <port> The program keeps a table of ten sites labeled site0 through site9. By using this command with '#' replaced by the appropriate digit, you can define new servers. A server has <name> as its shorthand reference, <address> as a fully qualified internet address, and port number <port>. By changing site0, you can change the default site which is used if .B igc is invoked without parameters. By default, the first three sites are set as described under command line options. The remaining seven sites are undefined. .SH BUGS .LP Text the server sends before the Login: prompt is not displayed .LP Login message isn't displayed when logging into accounts not in client mode .LP Sometimes you'll get a "premature move" error when starting a game. If this happens you must restart your game. .LP The server doesn't correctly mark the ends of games, so if a game ends while you are playing/observing, the client may still think you are playing/observing. The number in the upper left will say '--' if the client realizes you are not doing anything. If it doesn't, press return a few times in the server window. .LP If someone who is playing a game changes their rank, the change will not be reflected on the screens of other people watching or playing that game. .LP If komi changes during a game, the observers will not see the change. (The players will.) .LP Sometimes when you observe a game, a move may get lost. .LP The program cannot handle boards larger than 19x19. .SH AUTHOR Adrian Mariano (adrian@u.washington.edu, adrian on IGS) .SH SEE ALSO LaTeX and Postscript documentation for the IGS is available on ftp.u.washington.edu in public/go/prog/igs.tex.Z and public/go/prog/igs.ps.Z. .LP Other programs: mgt, pcigc, stigc, xigc, xgospel SHAR_EOF fi exit 0 # End of shell archive